home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-04-30 | 39.3 KB | 1,273 lines |
- (*----------------------------------------------------------------------*)
- (* Do_CompuServe_B_Transfer --- Do Compuserve B Protocol transfer *)
- (*----------------------------------------------------------------------*)
-
- FUNCTION CompuServe_B_Transfer : BOOLEAN;
-
- (*----------------------------------------------------------------------*)
- (* *)
- (* Routine: CompuServe_B_Transfer *)
- (* *)
- (* Purpose: Executes CompuServe B protocol transfers *)
- (* *)
- (* Calling Sequence: *)
- (* *)
- (* OK := CompuServe_B_Transfer : BOOLEAN; *)
- (* *)
- (* OK --- set TRUE if transfer went OK *)
- (* *)
- (* Calls: None *)
- (* *)
- (* Called by: Emulate_VT52 *)
- (* Emulate_ANSI *)
- (* *)
- (* Remarks: *)
- (* *)
- (* This code is taken from some prepared by Jim Nutt. *)
- (* *)
- (*----------------------------------------------------------------------*)
-
- CONST
- Xmt_Size = 511;
- Rcv_Size = 512;
- Max_Errors = 10;
-
- (* Sender Actions *)
-
- S_Send_packet = 0;
- S_Get_DLE = 1;
- S_Get_num = 2;
- S_Get_seq = 3;
- S_Get_data = 4;
- S_Get_CheckSum = 5;
- S_Timed_Out = 6;
- S_Send_NAK = 7;
-
- (* Receiver Actions *)
-
- R_Get_DLE = 0;
- R_Get_b = 1;
- R_Get_seq = 2;
- R_Get_data = 3;
- R_Get_CheckSum = 4;
- R_Send_NAK = 5;
- R_Send_ACK = 6;
-
- (* Other Constants *)
-
- xmt_col = 50;
- rcv_col = 36;
- xon = 17;
- xoff = 19;
- dle = 16;
- etx = 03;
- nak = 21;
- ENQ = 05;
- wack = 59;
-
- Err_Mess_Line = 5 (* Line for status report *);
-
- TYPE
- BufferType = ARRAY[0..520] OF BYTE;
-
- VAR
- Timer : INTEGER;
- R_Size : INTEGER (* size of receiver buffer *);
- CheckSum : INTEGER;
- Seq_Num : INTEGER;
- Ch : INTEGER; (* current character *)
-
- Xoff_Flag : BOOLEAN;
- Masked : BOOLEAN; (* TRUE if ctrl character was 'Masked' *)
-
- S_Buffer : BufferType;
- R_Buffer : BufferType;
- FileName : AnyStr (* PathName *);
- i : INTEGER;
- n : INTEGER;
- Dummy : BOOLEAN;
-
- Comp_Title : AnyStr;
- Total_Blocks : INTEGER (* Blocks processed so far *);
- Total_Packets : INTEGER (* Packets thus far *);
- Total_Errors : INTEGER (* Errors thus far *);
- Total_Bytes : REAL (* Bytes thus far *);
- TFile_Size : REAL (* Size of file to send *);
-
- Halt_Transfer : BOOLEAN (* Keypressed to halt transfer *);
- Receiving_File: BOOLEAN (* TRUE if receiving file *);
-
- Starting_Time : REAL (* Start time of transfer *);
- Ending_Time : REAL (* End time of transfer *);
- Total_Time : REAL (* Total transfer time *);
- Reset_Port : BOOLEAN (* TRUE if port needs reset *);
-
- LABEL
- Error_Exit;
-
- (*----------------------------------------------------------------------*)
- (* Initialize_Transfer_Display --- Initialize transfer display window *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Initialize_Transfer_Display;
-
- BEGIN (* Initialize_Transfer_Display *)
-
- Draw_Menu_Frame( 5, 10, 75, 16, Menu_Frame_Color, Menu_Title_Color,
- Menu_Text_Color, Comp_Title );
-
- TextColor( Menu_Text_Color_2 );
-
- GoToXY( 1 , 1 );
- WRITE('Packets transferred: ');
-
- GoToXY( 1 , 2 );
- WRITE('Bytes transferred: ');
-
- GoToXY( 1 , 3 );
- WRITE('Total errors: ');
-
- GoToXY( 1 , 4 );
-
- IF ( NOT Receiving_File ) THEN
- WRITE('Bytes to send: ');
-
- ClrEol;
-
- GoToXY( 1 , Err_Mess_Line );
- WRITE('Last status message: ');
-
- CursorOff;
-
- TextColor( Menu_Text_Color );
-
- Write_Log( Comp_Title, FALSE, FALSE );
-
- END (* Initialize_Transfer_Display *);
-
- (*----------------------------------------------------------------------*)
- (* Update_B_Display --- Update blocks received display *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Update_B_Display;
-
- BEGIN (* Update_B_Display *)
-
- IF Display_Status THEN
- BEGIN
-
- TextColor( Menu_Text_Color );
-
- GoToXY( 22 , 1 );
- WRITE( Total_Packets:8 );
- ClrEol;
-
- GoToXY( 22 , 2 );
- WRITE( Total_Bytes:8:0 );
- ClrEol;
-
- GoToXY( 22 , 3 );
- WRITE( Total_Errors:8 );
- ClrEol;
-
- IF ( NOT Receiving_File ) THEN
- BEGIN
- GoToXY( 22 , 4 );
- WRITE( TFile_Size:8:0 );
- ClrEol;
- END;
-
- END;
-
- END (* Update_B_Display *);
-
- (*----------------------------------------------------------------------*)
- (* Flip_Display_Status --- turn status display on/off *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Flip_Display_Status;
-
- BEGIN (* Flip_Display_Status *)
-
- CASE Display_Status OF
-
- TRUE: BEGIN
- (* Indicate no display *)
-
- Display_Status := FALSE;
-
- (* Remove display window *)
-
- Restore_Screen( Saved_Screen );
-
- Reset_Global_Colors;
-
- (* Restore cursor *)
- CursorOn;
-
- END;
-
- FALSE: BEGIN
- (* Indicate display will be done *)
-
- Display_Status := TRUE;
-
- (* Save screen image *)
-
- Save_Partial_Screen( Saved_Screen, 5, 10, 75, 16 );
-
- (* Initialize display window *)
-
- Initialize_Transfer_Display;
-
- END;
-
- END (* CASE *);
-
- END (* Flip_Display_Status *);
-
- (*----------------------------------------------------------------------*)
- (* Display_Message --- Display message in transfer window *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Display_Message( Message: AnyStr );
-
- BEGIN (* Display_Message *)
-
- IF ( NOT Display_Status ) THEN
- Flip_Display_Status;
-
- TextColor( Menu_Text_Color );
-
- GoToXY( 22 , Err_Mess_Line );
- WRITE( Message );
- ClrEol;
-
- Write_Log( Message, TRUE, FALSE );
-
- END (* Display_Message *);
-
- (*----------------------------------------------------------------------*)
- (* Display_Message_With_Number --- Display message with a number *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Display_Message_With_Number( Message: AnyStr; Number: INTEGER );
-
- VAR
- S: STRING[10];
-
- BEGIN (* Display_Message_With_Number *)
-
- IF ( NOT Display_Status ) THEN
- Flip_Display_Status;
-
- TextColor( Menu_Text_Color );
-
- GoToXY( 22 , Err_Mess_Line );
- WRITE( Message , Number );
- ClrEol;
-
- STR( Number , S );
-
- Write_Log( Message + S, TRUE, FALSE );
-
- END (* Display_Message_With_Number *);
-
- (*----------------------------------------------------------------------*)
- (* Check_Keyboard --- Check for keyboard entry *)
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Check_Keyboard;
-
- VAR
- Ch: CHAR;
-
- BEGIN (* Check_Keyboard *)
-
- IF KeyPressed THEN
- BEGIN
-
- READ( Kbd, Ch );
-
- IF ( Ch = CHR( ESC ) ) THEN
- IF KeyPressed THEN
- BEGIN
- READ( Kbd , Ch );
- CASE ORD( Ch ) OF
- Alt_R: IF Receiving_File THEN
- Halt_Transfer := TRUE;
- Alt_S: IF ( NOT Receiving_File ) THEN
- Halt_Transfer := TRUE;
- Shift_Tab: Flip_Display_Status;
- ELSE Handle_Function_Key( Ch );
- END;
- END
- ELSE
- IF Async_XOff_Received THEN
- BEGIN
- Async_XOff_Received := FALSE;
- IF Do_Status_Line THEN
- Write_To_Status_Line( ' ', 65 );
- EXIT;
- END;
-
- IF Print_Spooling THEN
- Print_Spooled_File;
-
- END;
-
- END (* Check_Keyboard *);
-
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Send_Masked_Byte( Ch : INTEGER );
-
- BEGIN (* Send_Masked_Byte *)
-
- IF ( Ch < 32 ) THEN
- BEGIN
- Async_Send( CHR( DLE ) );
- Async_Send( CHR( Ch + ORD('@') ) );
- END
- ELSE
- Async_Send( CHR( Ch ) );
-
- END (* Send_Masked_Byte *);
-
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Send_ACK;
-
- BEGIN (* Send_ACK *)
-
- Async_Send( CHR( DLE ) );
- Async_Send( CHR( Seq_Num + ORD('0') ) );
-
- Update_B_Display;
-
- END (* Send_ACK *);
-
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Send_NAK;
-
- BEGIN (* Send_NAK *)
-
- Display_Message_With_Number( 'Sending NAK for block ', Total_Blocks );
-
- Async_Send( CHR( NAK ) );
-
- Update_B_Display;
-
- END (* Send_NAK *);
-
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Send_ENQ;
-
- BEGIN (* Send_ENQ *)
-
- Async_Send( CHR( ENQ ) );
-
- END (* Send_ENQ *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Read_Byte : BOOLEAN;
-
- VAR
- I: INTEGER;
-
- BEGIN (* Read_Byte *)
-
- I := 0;
-
- REPEAT
- I := I + 1;
- Async_Receive_With_Timeout( 1 , Ch );
- Check_Keyboard;
- UNTIL ( I > Timer ) OR ( Ch <> TimeOut ) OR Halt_Transfer;
-
- Read_Byte := ( Ch <> TimeOut ) AND
- ( I <= Timer ) AND
- ( NOT Halt_Transfer );
-
- END (* Read_Byte *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Read_Masked_Byte : BOOLEAN;
-
- BEGIN (* Read_Masked_Byte *)
-
- Masked := FALSE;
-
- IF NOT Read_Byte THEN
- BEGIN
- Read_Masked_Byte := FALSE;
- EXIT;
- END;
-
- IF ( Ch = DLE ) THEN
- BEGIN
-
- IF NOT Read_Byte THEN
- BEGIN
- Read_Masked_Byte := FALSE;
- EXIT;
- END;
-
- Ch := Ch AND $1F;
-
- Masked := TRUE;
-
- END;
-
- Read_Masked_Byte := TRUE;
-
- END (* Read_Masked_Byte *);
-
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Do_CheckSum( Ch : INTEGER );
-
- BEGIN (* Do_CheckSum *)
-
- CheckSum := CheckSum SHL 1;
-
- IF ( CheckSum > 255 ) THEN
- CheckSum := ( CheckSum AND $FF ) + 1;
-
- CheckSum := CheckSum + Ch;
-
- IF ( CheckSum > 255 ) THEN
- CheckSum := ( CheckSum AND $FF ) + 1;
-
- END (* Do_CheckSum *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Send_Packet( size: INTEGER ) : BOOLEAN;
-
- VAR
- Action : INTEGER;
- Errors : INTEGER;
- Next_Seq : INTEGER;
- Block_Num : INTEGER;
- i : INTEGER;
- Sent_ENQ : BOOLEAN;
- Quit_Send : BOOLEAN;
-
- BEGIN (* Send_Packet *)
-
- Send_Packet := FALSE;
- Quit_Send := FALSE;
-
- Next_Seq := ( Seq_Num + 1 ) MOD 10;
-
- Total_Packets := Total_Packets + 1;
-
- Errors := 0;
-
- Sent_ENQ := FALSE;
-
- Action := S_Send_Packet;
-
- WHILE ( NOT ( Quit_Send OR Halt_Transfer ) ) DO
- BEGIN
-
- Check_KeyBoard;
-
- CASE Action OF
- S_Send_Packet: BEGIN
-
- CheckSum := 0;
-
- Async_Send( CHR( DLE ) );
- Async_Send( 'B' );
- Async_Send( CHR( Next_Seq + ORD('0') ) );
-
- Do_Checksum( Next_Seq + ORD('0') );
-
- FOR i := 0 TO Size DO
- BEGIN
- Send_Masked_Byte( S_Buffer[i] );
- Do_Checksum ( S_Buffer[i] );
- END;
-
- Async_Send( CHR( ETX ) );
-
- Do_Checksum( ETX );
-
- Send_Masked_Byte( CheckSum );
-
- Action := S_Get_DLE;
-
- END;
-
- S_Get_DLE: BEGIN
-
- Timer := 30;
-
- IF NOT Read_Byte THEN
- Action := S_Timed_Out
- ELSE IF ( Ch = DLE ) THEN
- Action := S_Get_num
- ELSE IF ( Ch = NAK ) THEN
- BEGIN
- Errors := Errors + 1;
- Total_Errors := Total_Errors + 1;
- IF ( Errors > Max_Errors ) THEN
- BEGIN
- Send_Packet := FALSE;
- Quit_Send := TRUE;
- END
- ELSE
- Action := S_Send_Packet;
- END
- ELSE IF ( Ch = ETX ) THEN
- Action := S_Send_NAK;
-
- END;
-
- S_Get_num: BEGIN
-
- Timer := 30;
-
- IF NOT Read_Byte THEN
- Action := S_Timed_Out
- ELSE IF ( Ch >= ORD('0') ) AND ( Ch <= ORD('9') ) THEN
- BEGIN
-
- IF ( ( Ch - ORD('0') ) = Seq_Num ) THEN
- IF Sent_ENQ THEN
- Action := S_Send_Packet
- ELSE Action := S_Get_DLE
- ELSE
- IF ( ( Ch - ORD('0') ) = Next_Seq ) THEN
- BEGIN
- Seq_Num := Next_Seq;
- Send_Packet := TRUE;
- Quit_Send := TRUE;
- END
- ELSE
- IF ( Errors = 0 ) THEN
- Action := S_Send_Packet
- ELSE
- Action := S_Get_DLE;
-
- END
- ELSE IF ( Ch = nak ) THEN
- Action := S_Send_Packet
- ELSE IF ( Ch = wack ) THEN
- BEGIN
- Timer := Timer + 10;
- Action := S_Get_DLE;
- END
- ELSE IF ( Ch = ORD('B') ) THEN
- Action := S_Get_seq
- ELSE IF ( Ch = etx ) THEN
- Action := S_Send_NAK
- ELSE
- Action := S_Get_DLE;
-
- END;
-
- S_Get_seq: BEGIN
-
- Timer := 10;
-
- IF NOT Read_Byte THEN
- Action := S_Send_NAK
- ELSE
- BEGIN
-
- CheckSum := 0;
-
- Block_Num := Ch - ORD('0');
-
- Do_Checksum( Ch );
-
- i := 0;
-
- Action := S_Get_data;
-
- END;
-
- END;
-
- S_Get_data: BEGIN
-
- Timer := 10;
-
- IF NOT Read_Masked_Byte THEN
- Action := S_Send_NAK
- ELSE IF ( ( Ch = etx ) AND ( NOT Masked ) ) THEN
- BEGIN
- Do_Checksum( ETX );
- Action := S_Get_CheckSum;
- END
- ELSE
- BEGIN
- R_Buffer[i] := Ch;
- i := i + 1;
- Do_Checksum( Ch );
- END;
-
- END;
-
- S_Get_CheckSum: BEGIN
-
- Timer := 10;
-
- IF ( NOT Read_Masked_Byte ) THEN
- Action := S_Send_NAK
- ELSE IF ( Ch <> CheckSum ) THEN
- Action := S_Send_NAK
- ELSE IF ( Block_Num <>
- ( ( Next_Seq + 1 ) mod 10 ) ) THEN
- Action := S_Send_NAK
- ELSE
- BEGIN
- Seq_Num := Block_Num;
- Send_ACK;
- R_Size := i;
- Send_Packet := TRUE;
- Quit_Send := TRUE;
- END;
-
- END;
-
- S_Timed_Out: BEGIN
-
- Errors := Errors + 1;
- Total_Errors := Total_Errors + 1;
-
- IF ( Errors > 4 ) THEN
- BEGIN
- Send_Packet := FALSE;
- Quit_Send := TRUE;
- END;
-
- Action := S_Get_DLE;
-
- END;
-
- S_Send_NAK: BEGIN
-
- Errors := Errors + 1;
- Total_Errors := Total_Errors + 1;
-
- IF ( Errors > Max_Errors ) THEN
- BEGIN
- Send_Packet := FALSE;
- Quit_Send := TRUE;
- END;
-
- Send_NAK;
-
- Action := S_Get_DLE;
-
- END;
-
- END (* CASE *);
-
- Update_B_Display;
-
- END (* BEGIN *);
-
- END (* Send_Packet *);
-
- (*----------------------------------------------------------------------*)
-
- PROCEDURE Send_Failure( Code : CHAR );
-
- VAR
- Dummy : BOOLEAN;
-
- BEGIN (* Send_Failure *)
-
- S_Buffer[0] := ORD( 'F' );
- S_Buffer[1] := ORD( Code );
-
- Dummy := Send_Packet( 2 );
-
- END (* Send_Failure *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Read_File( VAR Data_File : INTEGER;
- VAR S_Buffer : BufferType;
- n : INTEGER;
- Xmt_Size : INTEGER ) : INTEGER;
-
- VAR
- I : INTEGER;
- L : INTEGER;
-
- BEGIN (* Read_File *)
-
- L := Xmt_Size;
-
- I := Read_File_Handle( Data_File, S_Buffer[n], L );
-
- Read_File := L;
-
- END (* Read_File *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Send_File( Name : AnyStr ) : BOOLEAN;
-
- VAR
- N : INTEGER;
- Data_File : INTEGER;
- IO_Error : INTEGER;
- F : FILE OF BYTE;
- Cps_S : STRING[10];
- CPS : INTEGER;
- Send_Mess : AnyStr;
-
- LABEL Error;
-
- BEGIN (* Send_File *)
- (* Assume send fails *)
- Send_File := FALSE;
- (* Open file to be uploaded *)
-
- (*$I-*)
- ASSIGN( F , Name );
- RESET ( F );
- (*$I+*)
-
- IF ( Int24Result <> 0 ) THEN
- BEGIN
- Send_Failure('E');
- Display_Message('Can''t open file to be sent, transfer stopped.');
- GOTO Error;
- END;
-
- TFile_Size := LongFileSize( F );
-
- (*$I-*)
- CLOSE( F );
- (*$I+*)
-
- N := Int24Result;
-
- IO_Error := Open_File_Handle( Name , Access_Read_Mode , Data_File );
-
- (* If file can't be opened, halt *)
- (* transfer. *)
-
- IF ( IO_Error <> 0 ) OR ( N <> 0 ) THEN
- BEGIN
- Send_Failure('E');
- Display_Message('Can''t open file to be sent, transfer stopped.');
- GOTO Error;
- END;
- (* Remember starting time for transfer *)
- Starting_Time := TimeOfDay;
-
- REPEAT
- (* Read next sector of data *)
- S_Buffer[0] := ORD('N');
- N := Read_File( Data_File, S_Buffer, 1, Xmt_Size );
-
- (* Send data packet if anything *)
- (* to send. *)
- IF ( N > 0 ) THEN
- BEGIN
- (* If packet not sent, report *)
- (* failure. *)
-
- Total_Blocks := Total_Blocks + 1;
- Total_Bytes := Total_Bytes + N;
-
- IF ( NOT Send_Packet( n ) ) THEN
- BEGIN
- Display_Message('Can''t send packet, transfer stopped.');
- Halt_Transfer := TRUE;
- END;
-
- END;
- (* Check for keyboard input halting *)
- (* transfer. *)
-
- Check_Keyboard;
-
- IF Halt_Transfer THEN
- BEGIN
- Send_Failure('E');
- Display_Message('ESC key hit -- transfer terminated.');
- END;
-
- Update_B_Display;
-
- UNTIL ( N <= 0 ) OR Halt_Transfer;
-
- (* Close file *)
- Ending_Time := TimeOfDay;
- IO_Error := Close_File_Handle( Data_File );
-
- IF ( NOT Halt_Transfer ) THEN
- BEGIN
- (* Send end of file packet. *)
- S_Buffer[0] := ORD('T');
- S_Buffer[1] := ORD('C');
-
- IF ( NOT Send_Packet( 2 ) ) THEN
- Display_Message('Can''t send end of file packet, transfer stopped.')
- ELSE
- BEGIN
- Send_File := TRUE;
- Total_Time := TimeDiff( Starting_Time , Ending_Time );
- Send_Mess := 'Send complete.';
- IF ( Total_Time > 0 ) THEN
- BEGIN
- CPS := TRUNC( Total_Bytes / Total_Time );
- STR( CPS , Cps_S );
- Send_Mess := Send_Mess + ' Transfer rate: ' + Cps_S +
- ' CPS.';
- END;
- Display_Message( Send_Mess );
- END;
-
- END;
-
- Error:
- IF Reset_Port THEN
- Async_Reset_Port( Comm_Port, Baud_Rate,
- Xmodem_Parity_Save,
- Xmodem_Bits_Save,
- Xmodem_Stop_Save );
- Reset_Port := FALSE;
-
- DELAY( Two_Second_Delay );
-
- END (* Send_File *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Read_Packet : BOOLEAN;
-
- (* True if packet is available from host *)
-
- VAR
- Action : INTEGER;
- Next_Seq : INTEGER;
- Block_Num : INTEGER;
- Errors : INTEGER;
- i : INTEGER;
-
- BEGIN (* Read_Packet *)
-
- (* Clear out packet area *)
- FillChar( R_Buffer , 520 , 0 );
-
- (* Packet sequence number *)
-
- Next_Seq := ( Seq_Num + 1 ) MOD 10;
-
- Errors := 0;
- Action := R_Get_DLE;
- Total_Packets := Total_Packets + 1;
-
- (* Get next packet *)
- WHILE ( NOT Halt_Transfer ) DO
- BEGIN
-
- Check_KeyBoard;
-
- Timer := 10;
-
- CASE Action OF
-
- R_Get_DLE: BEGIN
-
- IF ( NOT Read_Byte ) THEN
- Action := R_Send_NAK
- ELSE IF ( ( Ch AND $7F ) = dle ) THEN
- Action := R_Get_b
- ELSE IF ( ( Ch AND $7F ) = ENQ ) THEN
- Action := R_Send_ACK;
- END;
-
- R_Get_b: BEGIN
-
- IF ( NOT Read_Byte ) THEN
- Action := R_Send_NAK
- ELSE IF ( ( Ch AND $7F ) = ORD('B') ) THEN
- Action := R_Get_seq
- ELSE IF ( Ch = ENQ ) THEN
- Action := R_Send_ACK
- ELSE
- Action := R_Get_DLE;
- END;
-
- R_Get_seq: BEGIN
-
- IF ( NOT Read_Byte ) THEN
- Action := R_Send_NAK
- ELSE IF ( Ch = ENQ ) THEN
- Action := R_Send_ACK
- ELSE
- BEGIN
- CheckSum := 0;
- Block_Num := Ch - ORD('0');
- Do_Checksum( Ch );
- i := 0;
- Action := R_Get_data;
- END;
-
- END;
-
- R_Get_data: BEGIN
-
- IF ( NOT Read_Masked_Byte ) THEN
- Action := R_Send_NAK
- ELSE IF ( ( Ch = etx ) AND ( NOT Masked ) ) THEN
- BEGIN
- Do_Checksum( etx );
- Action := R_Get_CheckSum;
- END
- ELSE
- BEGIN
- R_Buffer[i] := Ch;
- i := i + 1;
- Do_Checksum( Ch );
- END;
-
- END;
-
- R_Get_CheckSum: BEGIN
-
- IF ( NOT Read_Masked_Byte ) THEN
- Action := R_Send_NAK
- ELSE IF ( Ch <> CheckSum ) THEN
- Action := R_Send_NAK
- ELSE IF ( Block_Num = Seq_Num ) THEN
- BEGIN
- IF ( R_Buffer[0] = ORD('F') ) THEN
- BEGIN
- Seq_Num := Block_Num;
- R_Size := i;
- Read_Packet := TRUE;
- EXIT;
- END
- ELSE
- Action := R_Send_ACK;
- END
- ELSE IF ( Block_Num <> Next_Seq ) THEN
- Action := R_Send_NAK
- ELSE
- BEGIN
- Seq_Num := Block_Num;
- R_Size := i;
- Read_Packet := TRUE;
- EXIT;
- END;
-
- END;
-
- R_Send_NAK: BEGIN
-
- Errors := Errors + 1;
- Total_Errors := Total_Errors + 1;
-
- IF ( Errors > Max_Errors ) THEN
- BEGIN
- Read_Packet := FALSE;
- EXIT;
- end;
-
- Send_NAK;
-
- Action := R_Get_DLE;
-
- END;
-
- R_Send_ACK: BEGIN
- (* wait for the next block *)
-
- Send_ACK;
- Action := R_Get_DLE;
-
- END;
-
- END (* CASE *);
-
- END (* WHILE *);
-
- END (* Read_Packet *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Write_File( VAR Data_File : INTEGER;
- R_Buffer : BufferType;
- n : INTEGER;
- size : INTEGER) : INTEGER;
-
- BEGIN (* Write_File *)
-
- Write_File := Write_File_Handle( Data_File, R_Buffer[ n ], size );
-
- END (* Write_File *);
-
- (*----------------------------------------------------------------------*)
-
- FUNCTION Receive_File( Name : AnyStr ) : BOOLEAN;
-
- VAR
- Data_File : INTEGER;
- Status : INTEGER;
- R_File : BOOLEAN;
- Cps_S : STRING[10];
- CPS : INTEGER;
- Rec_Mess : AnyStr;
-
- LABEL Error;
-
- BEGIN (* Receive_File *)
- (* Assume transfer fails *)
- R_File := FALSE;
- (* Open file to be created *)
- IF ( POS( ':' , Name ) = 0 ) AND
- ( POS( '\' , Name ) = 0 ) THEN
- Name := Download_Dir_Path + Name;
-
- Status := Create_File_Handle( Name, Attribute_None, Data_File );
-
- (* Halt transfer if file can't be *)
- (* opened. *)
- IF ( Status <> 0 ) THEN
- BEGIN
- Send_Failure('E');
- Display_Message('Can''t open output file, transfer stoppped.');
- Receive_File := FALSE;
- GOTO Error;
- END;
- (* Send ACK to start transfer *)
- Send_ACK;
- (* Remember starting time for transfer *)
- Starting_Time := TimeOfDay;
- (* Begin loop over packets *)
-
- WHILE ( NOT ( Halt_Transfer OR R_File ) ) DO
- BEGIN
- (* Get next packet *)
- IF Read_Packet THEN
- BEGIN
- (* Select Action based upon packet type *)
-
- CASE CHR( R_Buffer[0] ) OF
-
- (* Data for file -- write it and *)
- (* acknowledge it. *)
- 'N': BEGIN
- Status := Write_File( Data_File, R_Buffer, 1,
- R_Size - 1 );
- Send_ACK;
- Total_Blocks := Total_Blocks + 1;
- Total_Bytes := Total_Bytes + R_Size - 1;
- END;
- (* End of transfer -- close file *)
- (* and acknowledge end of file *)
- 'T': BEGIN
-
- IF ( R_Buffer[1] = ORD('C') ) THEN
- BEGIN
- Ending_Time := TimeOfDay;
- Status := Close_File_Handle( Data_File );
- Send_ACK;
- R_File := TRUE;
- Total_Time := TimeDiff( Starting_Time ,
- Ending_Time );
- Rec_Mess := 'Receive complete.';
- IF ( Total_Time > 0 ) THEN
- BEGIN
- CPS := TRUNC( Total_Bytes / Total_Time );
- STR( CPS , Cps_S );
- Rec_Mess := Rec_Mess + ' Transfer rate: ' + Cps_S +
- ' CPS.';
- END;
-
- Display_Message( Rec_Mess );
-
- END;
-
- END;
- (* Stop transfer received -- halt *)
- (* transfer and acknowledge. *)
- 'F': BEGIN
- Send_ACK;
- Halt_Transfer := TRUE;
- Display_Message('Host cancelled transfer.');
- END;
-
- END (* CASE *);
-
- END (* IF *);
- (* Check for keyboard input halting *)
- (* transfer. *)
- Check_Keyboard;
-
- IF Halt_Transfer THEN
- BEGIN
- Send_Failure('E');
- Display_Message('ESC key hit -- transfer terminated.');
- ClrEol;
- END;
-
- END (* WHILE *);
-
- Receive_File := R_File;
- Ending_Time := TimeOfDay;
- Status := Close_File_Handle( Data_File );
-
- Error:
- IF Reset_Port THEN
- Async_Reset_Port( Comm_Port, Baud_Rate,
- Xmodem_Parity_Save,
- Xmodem_Bits_Save,
- Xmodem_Stop_Save );
- Reset_Port := FALSE;
-
- DELAY ( Two_Second_Delay );
-
- END (* Receive_File *);
-
- (*--------------- CompuServe_B_Transfer --- main code -------------------*)
-
- BEGIN (* CompuServe_B_Transfer *)
-
- (* Reset comm parms to 8,n,1 *)
- Xmodem_Bits_Save := Data_Bits;
- Xmodem_Parity_Save := Parity;
- Xmodem_Stop_Save := Stop_Bits;
-
- IF ( ( Data_Bits = 8 ) AND ( Parity = 'N' ) ) THEN
- Reset_Port := FALSE
- ELSE
- BEGIN
- Async_Reset_Port( Comm_Port, Baud_Rate, 'N', 8, 1 );
- Reset_Port := TRUE;
- END;
-
- (* Announce protocol starts *)
-
- Save_Partial_Screen( Saved_Screen, 5, 10, 75, 16 );
-
- Comp_Title := 'CompuServe B Protocol';
-
- Receiving_File := TRUE;
-
- Initialize_Transfer_Display;
- (* Assume transfer goes OK *)
-
- CompuServe_B_Transfer := TRUE;
-
- Halt_Transfer := FALSE;
- Xoff_Flag := FALSE;
- Receiving_File := TRUE;
- Display_Status := TRUE;
- Seq_Num := 0;
- Comp_Title := 'CIS B -- ';
- Total_Blocks := 0;
- Total_Packets := 0;
- Total_Errors := 0;
- Total_Bytes := 0.0;
- (* ACKnowledge start of protocol *)
- Send_ACK;
- (* Read initial packet *)
- IF Read_Packet THEN
- BEGIN
- (* Select Action based upon packet type *)
-
- CASE CHR( R_Buffer[0] ) OF
-
- (* Upload or download *)
- 'T': BEGIN
-
- CASE CHR( R_Buffer[1] ) OF
- 'D' : BEGIN
- Comp_Title := 'Receiving ';
- Receiving_File := TRUE;
- END;
- 'U' : BEGIN
- Comp_Title := 'Sending ';
- Receiving_File := FALSE;
- END;
- ELSE
- BEGIN
- Send_Failure('N');
- CompuServe_B_Transfer := FALSE;
- GOTO Error_Exit;
- END;
- END (* CASE *);
-
- (* Get file name *)
-
- CASE CHR( R_Buffer[2] ) OF
- 'A': Comp_Title := Comp_Title + 'ASCII file "';
- 'B': Comp_Title := Comp_Title + 'Binary file "';
- ELSE
- BEGIN
- Send_Failure('N'); (* Not implemented *)
- CompuServe_B_Transfer := FALSE;
- GOTO Error_Exit;
- END;
- END (* CASE *);
-
- I := 2;
- FileName := '';
-
- WHILE ( R_Buffer[I] <> 0 ) AND ( I < R_Size ) DO
- BEGIN
- I := I + 1;
- FileName := FileName + CHR( R_Buffer[I] );
- END;
-
- Comp_Title := Comp_Title + FileName + '"';
-
- (* Display file transfer header *)
-
- Initialize_Transfer_Display;
-
- (* Perform transfer *)
-
- IF ( R_Buffer[1] = ORD('U') ) THEN
- Dummy := Send_File( FileName )
- ELSE
- Dummy := Receive_File( FileName );
-
- END;
-
- END (* CASE *);
-
- END (* IF *)
- (* No initial packet -- quit *)
- ELSE
- BEGIN
- Display_Message('Cannot receive initial packet, transfer cancelled');
- IF Reset_Port THEN
- Async_Reset_Port( Comm_Port, Baud_Rate, Xmodem_Parity_Save,
- Xmodem_Bits_Save, Xmodem_Stop_Save );
- Reset_Port := FALSE;
- DELAY( Two_Second_Delay );
- END;
-
- Error_Exit:
- (* Reset comm parms back *)
- IF Reset_Port THEN
- Async_Reset_Port( Comm_Port, Baud_Rate, Xmodem_Parity_Save,
- Xmodem_Bits_Save, Xmodem_Stop_Save );
-
- (* Restore previous screen *)
- Restore_Screen( Saved_Screen );
- Reset_Global_Colors;
- (* Restore cursor *)
- CursorOn;
-
- END (* CompuServe_B_Transfer *);